docs: document sink-visibility field in MCP Gateway write-sink guard policy (spec v1.15.0)#44305
Conversation
…spec - Add Section 4.1.3.8 documenting the new `forcePublicRepos` gateway config field - Add `forcePublicRepos` to the gateway config fields table (Section 4.1.3) - Add Section 10.8 — Write-Sink Guard Policy with full `sink-visibility` field specification, enforcement model, DIFC semantics, runtime verification, and compiler behavior - Add Section 10.9 — Cross-Visibility Opt-Out documenting `private-to-public-flows: allow` frontmatter option, its constraints, compiler responsibilities, and interaction matrix - Add compliance test category 11.1.12 with T-WS-001 through T-WS-008 - Update compliance checklist with Write-Sink Guard Policy row - Add changelog entry for spec version 1.15.0 - Update both JSON schema files (docs/public and pkg/workflow) with: - New `writeSinkGuardPolicyConfig` definition with `accept` and `sink-visibility` fields - Typed `write-sink` property in `guard-policies` for both stdioServerConfig and httpServerConfig - New `forcePublicRepos` boolean field in `gatewayConfig` - Added `guard-policies` to `stdioServerConfig` in docs/public schema (was missing) Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
…nition Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the MCP Gateway spec and its published/internal JSON schemas to formally specify cross-visibility protections against private-data leakage to public repositories, via the forcePublicRepos gateway behavior and the write-sink / sink-visibility DIFC policy.
Changes:
- Adds
gateway.forcePublicRepos(defaulttrue) to the spec and both JSON schemas, documenting runtime behavior and opt-out semantics. - Defines and documents
guard-policies.write-sinkwithaccept+ optionalsink-visibility(public|private|internal) in the spec and both JSON schemas. - Extends the MCP Gateway spec with a new compliance-test section for write-sink behavior (T-WS-001..T-WS-008) and updates the changelog/checklist.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/schemas/mcp-gateway-config.schema.json | Adds schema definitions for forcePublicRepos and typed guard-policies.write-sink to match the updated spec. |
| docs/public/schemas/mcp-gateway-config.schema.json | Publishes the same schema updates for documentation consumers (including stdio server guard-policies). |
| docs/src/content/docs/reference/mcp-gateway.md | Updates spec version to 1.15.0 and adds normative sections for forcePublicRepos, sink-visibility, opt-out semantics, and compliance tests. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 3/3 changed files
- Comments generated: 3
- Review effort level: Low
| #### 10.8.2 `sink-visibility` Field | ||
|
|
||
| The `write-sink` object inside `guard-policies` for a safe-outputs (or equivalent) MCP server accepts the following field: | ||
|
|
| This runtime expression resolves to the actual repository visibility at workflow execution time (as determined by the automatic lockdown detection step). Workflow authors do not need to set `sink-visibility` manually — it is derived from the repository context automatically. | ||
|
|
||
| **Configuration Example** (as rendered in the generated config): |
| When `forcePublicRepos` is `true` (the default), the gateway overrides the compiled allow-only policy to `repos="public"` at startup if it detects the workflow is running in a public repository. This prevents agents from accumulating private-data secrecy tags in the first place — even when the compiled config grants broader access. | ||
|
|
||
| **Detection mechanism**: The gateway reads `GITHUB_REPOSITORY` and calls `GET /repos/{owner}/{repo}` at startup to determine repository visibility. If the repository is public and `forcePublicRepos` is `true`, the override is applied unconditionally. | ||
|
|
|
@copilot use consistent among comventions |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Fixed three inconsistencies in the spec (commit
|
|
@copilot please run the
|
All local validation passes and the branch is up to date with Reviews: Three
GraphQL API returns 403 so threads cannot be programmatically resolved — they will dismiss when a reviewer re-reviews. Checks (local): Checks (CI): Stale after agent push; needs human re-trigger (close/reopen PR or push from maintainer). Mergeable: PR is open, not draft, branch is up to date. Hand-off: CI must be re-triggered by a maintainer before merge. |
💥 Smoke Test: Claude — Run 28952113419Core #1-12: ✅ all passed Overall: PARTIAL (all executed tests passed; 2 skipped) Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal!
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
💥 [THE END] — Illustrated by Smoke Claude · 64.8 AIC · ⌖ 31.5 AIC · ⊞ 8.4K
Comment /smoke-claude to run again
| }, | ||
| "default": ["*"] | ||
| }, | ||
| "guard-policies": { |
There was a problem hiding this comment.
Nice addition of the write-sink guard policy reference here — consider adding a schema example in the description for clarity.
| | `keepaliveInterval` | integer | No | Keepalive ping interval in seconds for HTTP MCP backends. Prevents session expiry during long-running tasks. Use `-1` to disable, `0` or unset for gateway default (1500s = 25 min), or a positive integer for a custom interval. | | ||
| | `sessionTimeout` | string | No | Session timeout for MCP gateway sessions as a Go duration string (e.g. `"30m"`, `"4h"`, `"24h"`). Empty or omitted uses the gateway default (6h). Must be at least 5m when set by the workflow compiler (no upper bound; infrastructure operators may override via `MCP_GATEWAY_SESSION_TIMEOUT` env var). | | ||
| | `opentelemetry` | object | No | OpenTelemetry configuration for emitting distributed tracing events for MCP calls. See Section 4.1.3.7 for details. | | ||
| | `forcePublicRepos` | boolean | No | When `true` (default), forces the allow-only policy to `repos="public"` at runtime if the gateway detects it is running in a public repository. When `false`, disables this override — set by the compiler when `private-to-public-flows: allow` is declared in workflow frontmatter. See Section 4.1.3.8 for details. | |
There was a problem hiding this comment.
Good documentation of forcePublicRepos — the default behavior is clearly explained. Consider cross-linking to the DIFC secrecy tags section.
|
Smoke test: FAIL Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
Comment MemoryNote This comment is managed by comment memory.It stores persistent context for this thread in the code block at the top of this comment. Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
Comment MemoryNote This comment is managed by comment memory.It stores persistent context for this thread in the code block at the top of this comment. Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
There was a problem hiding this comment.
Smoke run done. Two cave marks left inline.
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
📰 BREAKING: Report filed by Smoke Copilot · 98.6 AIC · ⌖ 4.87 AIC · ⊞ 19.1K
Comment /smoke-copilot to run again
Add label smoke to run again
|
Smoke tests:
Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
|
@copilot please run the
|
… net - Add sinkVisibilityExemptServers to gateway config fields table (section 4.1.3) - Add to JSON schemas in both docs/public and pkg/workflow - Document default sink-visibility="public" for non-safe-outputs (section 10.8.6) - Document safe-outputs runtime safety net (section 10.8.7) - Expand section 10.9 to support list form of private-to-public-flows - Add compiler responsibilities for list form (validation + config emission) - Update interaction matrix with list form compatibility Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
## Summary
Adds the same `forcePublicRepos` defense-in-depth runtime check to the
CLI proxy (`awmg proxy`) that already exists in the MCP gateway (unified
mode).
## Problem
The proxy receives its allow-only policy as a pre-built `--policy` JSON
string from the compiler. If the compiler misconfigures the policy
(e.g., `repos: "all"` when the workflow repo is public), the proxy would
trust it and allow the agent to read private repos through the `gh` CLI.
## Solution
Before passing the policy to the WASM guard, the proxy now:
1. Reads `GITHUB_REPOSITORY`
2. Calls `GET /repos/{owner}/{repo}` to verify visibility
3. If the repo is **public**, overrides `repos` to `"public"` in the
allow-only policy
This prevents agents in public-repo workflows from reading private
repos, regardless of what policy the compiler passed.
## Opt-out
Set `MCP_GATEWAY_FORCE_PUBLIC_REPOS=false` to disable (set by the
compiler when `private-to-public-flows: allow` is declared in workflow
frontmatter).
## Fail-open semantics
The override is skipped when:
- `MCP_GATEWAY_FORCE_PUBLIC_REPOS=false`
- `GITHUB_REPOSITORY` is not set
- No GitHub token is available
- The API call fails
In these cases, the compiled policy is used as-is.
## Companion PR
- github/gh-aw#44305 — spec documentation for `forcePublicRepos` and
sink-visibility
|
🎉 This pull request is included in a new release. Release: |
Adds formal spec coverage for the two complementary defenses against the GitLost vulnerability class (private data leaking to public repos via agentic workflows):
sink-visibility(output-side DIFC filtering) andforcePublicRepos(input-side repo access restriction).MCP Gateway spec (
mcp-gateway.md)forcePublicReposgateway config field: whentrue(default), overrides the allow-only policy torepos="public"at runtime if the gateway detects a public repository. Disabled viaMCP_GATEWAY_FORCE_PUBLIC_REPOS=falseor by the compiler whenprivate-to-public-flows: allowis set.sink-visibilityfield semantics, the DIFC enforcement model ("public"unconditionally sets resource secrecy to{}, blocking any tainted agent regardless ofaccept), runtime verification behavior (defense-in-depth override at startup), and the compiler-emitted runtime expression.private-to-public-flows: allowfrontmatter, its incompatibility withguards_mode: strict, compiler responsibilities, and the full interaction matrix.JSON Schemas (both
docs/public/andpkg/workflow/)writeSinkGuardPolicyConfigdefinition withaccept(required) andsink-visibility(optional enum:"public" | "private" | "internal").write-sinkproperty added toguard-policiesin bothstdioServerConfigandhttpServerConfig(thedocs/publicschema was missingguard-policieson stdio servers entirely).forcePublicRepos: booleanadded togatewayConfig.{ "mcpServers": { "safe-outputs": { "guard-policies": { "write-sink": { "accept": ["*"], "sink-visibility": "public" } } } }, "gateway": { "forcePublicRepos": false } }The
sink-visibilityvalue is emitted as a runtime expression by the compiler (${{ toJSON(steps.determine-automatic-lockdown.outputs.visibility) }}), so workflow authors do not set it manually.✨ PR Review Safe Output Test - Run 28952113419
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.comSee Network Configuration for more information.